{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Interactive Sensitivity Analysis \n", "\n", "## Try me\n", " [![Open In Colab](../../_static/colabs_badge.png)](https://colab.research.google.com/github/ffraile/operations-research-notebooks/blob/main/docs/source/CLP/tutorials/Sensitivity%20analysis%20interactive.ipynb)[![Binder](../../_static/binder_badge.png)](https://mybinder.org/v2/gh/ffraile/operations-research-notebooks/main?labpath=docs%2Fsource%2FCLP%2Ftutorials%2FSensitivity%20analysis%20interactive.ipynb)\n", "\n", "## Introduction\n", "In this notebook, you can experiment with the graphic representation of a linear programming problem. The objective is \n", "to assess the impact that the changes in the problem coefficient have in the optimal solution.\n", "\n", "## Problem model\n", "The problem model is taken from the Production Mix problem: \n", "\n", "$max Z = 300x_{1} + 250x_{2} + 0s_{1} + 0s_{2} + 0s_{3}$\n", "\n", "And the constraints as:\n", "\n", "$2x_{1} + x_{2} + s_{1} = 40$ \n", "$x_{1} + 3x_{2} + s_{2} = 45$ \n", "$x_{1} + s_{3} = 12$ \n" ] }, { "cell_type": "markdown", "source": [ "## Changes in the objective function coefficient\n", "The code cell below allows you to modify the coefficients of the objective function through sliders, to see how these changes\n", "modify the slope of the objective function. Depending on the changes, the optimal solution might be at another vertex, \n", "so the objective function slider allows to modify the objective variable z to find the optimal value in these cases. \n", "Remember, the optimal value will be always the highest value of z where the objective function intersects with the \n", "feasibility region. " ], "metadata": { "collapsed": false } }, { "cell_type": "code", "execution_count": 1, "outputs": [], "source": [ "#Import the numpy and pyplot libraries, we set the aliases np and plt so that it is easier to use \n", "import numpy as np\n", "import matplotlib.pyplot as plt\n", "import ipywidgets as widgets\n", "from ipywidgets import interactive\n", "#We set the mode inline of matplotlib to get the result at the output of the cell code\n", "%matplotlib inline\n", "\n", "#Construct lines, in our coordinate system x represents our decision variable x1 and y represents our decision variable x2\n", "x=np.linspace(0,30,2000) #2000 numbers from 0 to 30\n", "\n", "def show_solution(z=6350, c1=300, c2=250):\n", " \n", " y1=40 - 2*x # Operator time constraint\n", " y2=15-x/3 # Machining time constraint\n", " \n", " plt.figure(1)\n", "\n", " #1. Make plot\n", " plt.plot(x, y1, label=r'$2x_{1} + x_{2} \\leq 40$', c='orange', ls='dashed') #Plot y1\n", " plt.plot(x, y2, label=r'$x_{1} + 3x_{2} \\leq 45$', c='red') #Plot y2\n", " plt.axvline(x=12, label=r'$x_{1} \\leq 12$', c='green') #plot y3\n", "\n", " #2. Adjust axis\n", " plt.xlim((0, 30))\n", " plt.ylim((0, 45))\n", " plt.xlabel(r'$x_{1}$')\n", " plt.ylabel(r'$x_{2}$')\n", "\n", " #3. Fill feasible region\n", " y4=np.minimum(y1, y2) #line representing the maximum between y3 and y2\n", " plt.fill_between(x, y4, 0, where=x<12, color='grey', alpha=0.5) #fill where y5 ys greater than y6\n", "\n", " \n", " #4 Annotate graph\n", " plt.annotate('A', xy=(0, 0))\n", " plt.annotate('B', xy=(0, 15))\n", " plt.annotate('D',xy=(12, 0))\n", " plt.annotate('E', xy=(12,11))\n", "\n", " # 5. Plot objective function\n", " obj_func= (z - c1*x)/c2 # we clear the x2 with the value of z\n", " plt.plot(x, obj_func, label=r'$z = c_1*x_1 + c_2*x_2$', c='black')\n", "\n", " # 6. Plot legend\n", " plt.legend(bbox_to_anchor=(1.05,1), loc=2, borderaxespad=0.)\n", "\n", " plt.show()\n", "\n", "interactive_plot = interactive(show_solution, z=(3000,15000,10), c1=(10,500,10), c2=(100,1000,10))\n", "output = interactive_plot.children[-1]\n", "output.layout.height = '350px'\n", "interactive_plot" ], "metadata": { "collapsed": false } }, { "cell_type": "markdown", "source": [ "## Analysis questions\n", "1. Keep the objective function coefficient of the second variable to 250 and **decrease** the coefficient of the first variable. What happens to the slope of the objective function? Adjust the value of z until you find again the optimal value of the objective function. What happens to the optimal value of the objective function? Will it be always at the same vertex?\n", "2. Now, repeat the experiment in the first question and **increase** the coefficient of the first variable. What happens to the slope of the objective function? Adjust the value of z until you find again the optimal value of the objective function. What happens to the optimal value of the objective function? Do you think it will always be at the same vertex?\n", "3. Repeat the experiment in the first two questions but now changing the coefficient of the second variable and write down your conclusions." ], "metadata": { "collapsed": false } }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Changes in the constraint independent terms\n", "The code cell below allows you to modify the independent terms of the constraints. The changes are going to change the \n", "feasibility region and again, if they are too extreme, the solution might change to another vertex." ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "#Import the numpy and pyplot libraries, we set the aliases np and plt so that it is easier to use \n", "import numpy as np\n", "import matplotlib.pyplot as plt\n", "import ipywidgets as widgets\n", "from ipywidgets import interactive\n", "#We set the mode inline of matplotlib to get the result at the output of the cell code\n", "%matplotlib inline\n", "\n", "#Construct lines, in our coordinate system x represents our decision variable x1 and y represents our decision variable x2\n", "x=np.linspace(0,50,2000) #2000 numbers from 0 to 30\n", "\n", "\n", "\n", "\n", "\n", "def show_solution(z=6350, b1=40, b2=45, b3=12):\n", " \n", " y_min=x*0 # non negativity constraint\n", " y_max = 250 + 0*x \n", " \n", " y1 = b1 - 2*x # Operator time constraint\n", " y2=b2/3-x/3 # Machining time constraint\n", "\n", " plt.figure(1)\n", "\n", " #1. Make plot\n", " plt.plot(x, y1, label=r'$2x_{1} + x_{2} \\leq b_1$', c='orange') #Plot y1\n", " plt.plot(x, y2, label=r'$x_{1} + 3x_{2} \\leq b_2$', c='red') #Plot y2\n", " plt.axvline(x=b3, label=r'$x_{1} \\leq b_3$', c='green') #plot y3\n", "\n", " #2. Adjust axis\n", " plt.xlim((0, 50))\n", " plt.ylim((0, 45))\n", " plt.xlabel(r'$x_{1}$')\n", " plt.ylabel(r'$x_{2}$')\n", "\n", " #3. Fill feasible region\n", " y4=np.minimum(y1, y2) #line representing the maximum between y3 and y2\n", " plt.fill_between(x, y4, 0, where=x